package com.gs.netty.support.handler.method;


import com.gs.netty.core.handler.method.AbstractHandlerMethod;
import com.gs.netty.core.handler.method.HandlerMethod;
import com.gs.netty.websocket.remoting.req.Request;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

public class InvocableHandlerMethod extends AbstractHandlerMethod<Request> {

    public InvocableHandlerMethod(String beanName, Method method, BeanFactory beanFactory) {
        super(beanName, method, beanFactory);
    }

    public InvocableHandlerMethod(HandlerMethod handlerMethod) {
        super(handlerMethod, handlerMethod.getBean());
    }

    public InvocableHandlerMethod(Object bean, Method method) {
        super(bean, method);
    }


    @Override
    public void invokeAndHandle(Request request, Object... providedArgs) throws Throwable {
        /**
         * 获取参数
         */
        Object[] args =  getMethodArgumentValues(request,providedArgs);
        // 执行
        Object returnValue = doInvoke(args);
        if (returnValue == null) {
            return;
        }
        try {
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), request);
        }
        catch (Exception ex) {
            throw ex;
        }

    }


    private Object[] getMethodArgumentValues(Request request, Object ... providedArgs) throws Exception {
        // 获取方法参数
        MethodParameter[] parameters = getParameters();

        // 没有参数返回空参数
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        Object[] args = new Object[parameters.length];

        for (int i = 0; i < parameters.length; i++) {

            MethodParameter parameter = parameters[i];

            args[i] = findProvidedArgument(parameter, providedArgs);

            if (args[i] != null) {
                continue;
            }
            // 判断是否有参数解析器支持该参数解析。
            if (!this.argumentResolvers.supportsParameter(parameter)) {
                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                // 解析
                args[i] = this.argumentResolvers.resolveArgument(parameter, request);
            }
            catch (Exception ex) {
                throw ex;
            }
        }

        return args;
    }


    protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
        if (!ObjectUtils.isEmpty(providedArgs)) {
            for (Object providedArg : providedArgs) {
                if (parameter.getParameterType().isInstance(providedArg)) {
                    return providedArg;
                }
            }
        }
        return null;
    }

    protected static String formatArgumentError(MethodParameter param, String message) {
        return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
                param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
    }
}
